package com.jackrain.nea.shiro.stateful;

import com.jackrain.nea.shiro.Filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.BeanInitializationException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by Lucky dog on 2016/10/20.
 */
@Slf4j
public class MShiroFilterFactoryBean extends ShiroFilterFactoryBean {

    // 对ShiroFilter来说，需要直接忽略的请求
    private Set<String> ctlExt;

    public MShiroFilterFactoryBean() {
        super();
        //类型
        ctlExt = new HashSet<>();
//        ignoreExt.add(".js");
//        ignoreExt.add(".css");
//        ignoreExt.add(".map");
//        ignoreExt.add(".jpg");
//        ignoreExt.add(".png");


        //路径
//        ignoreExt.add("/fonts/");
//        ignoreExt.add("/img/");
//        ignoreExt.add("/css/");
//        ignoreExt.add("/js/");
//        ignoreExt.add("/404/");
//        ignoreExt.add("/403/");
//        ignoreExt.add("/500/");
//        ignoreExt.add("/");

        ctlExt.add("/app/tpl/ctl/");
        ctlExt.add("/p/c/login");
        ctlExt.add("/p/c/thirdlogin");
        ctlExt.add("/p/c/rememberMeLogin");
        ctlExt.add("/p/cs/");
        ctlExt.add("/c/");

        //ignoreExt.add("/app/layout/index");
        //ignoreExt.add("/app/layout/test");

    }

    @Override
    protected AbstractShiroFilter createInstance() throws Exception {

        SecurityManager securityManager = getSecurityManager();
        if (securityManager == null) {
            String msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        }

        if (!(securityManager instanceof WebSecurityManager)) {
            String msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        }

        FilterChainManager manager = createFilterChainManager();

        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);

        return new MSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

    private final class MSpringShiroFilter extends AbstractShiroFilter {

        protected MSpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
            super();
            if (webSecurityManager == null) {
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            }
            setSecurityManager(webSecurityManager);
            if (resolver != null) {
                setFilterChainResolver(resolver);
            }
        }

        @Override
        protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
                                        FilterChain chain) throws ServletException, IOException {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            String str = request.getRequestURI();
            // 因为ShiroFilter 拦截所有请求（在上面我们配置了urlPattern 为 * ，当然你也可以在那里精确的添加要处理的路径，这样就不需要这个类了），而在每次请求里面都做了session的读取和更新访问时间等操作，这样在集群部署session共享的情况下，数量级的加大了处理量负载。
            // 所以我们这里将一些能忽略的请求忽略掉。
            // 当然如果你的集群系统使用了动静分离处理，静态资料的请求不会到Filter这个层面，便可以忽略。
            boolean flag = false;
            int idx = 0;
            String tmp;
            if(str.length()>1&&ctlExt.stream().filter(num -> str.startsWith(num)).count()>=1) {
                flag = true;
            }

            if(flag){
                log.debug("do shirofilter->"+str);
                super.doFilterInternal(servletRequest, servletResponse, chain);
            }else{
                chain.doFilter(servletRequest, servletResponse);
            }
        }

    }
}
